﻿using Infrastructure.Attribute;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using ZR.DataCollection.Helper;
using ZR.DataCollection.ICommunication;
using ZR.DataCollection.InterfaceClass;
using ZR.DataCollection.SingleParameter;
using ZR.Model.Models.ProductionControl;
using ZR.Service.IService.ProductionControl;
using ZR.Service.Service.ProductionControl;
using ZR.ServiceCore.Model.Dto;
using ZR.ServiceCore.Signalr;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace ZR.DataCollection.Execute
{
    /// <summary>
    /// 故障监控
    /// </summary>
    [AppService(ServiceType = typeof(IExecuteWork), ServiceLifetime = LifeTime.Singleton)]
    public class ExecuteFaultWork : IExecuteWork
    {
        private readonly IFaultLargeGroupService _faultLargeGroupService;
        private readonly IFaultSubclassDetailsService _faultSubclassDetailsService;
        private readonly IFaultLogService _faultLogService;
        private readonly IHubContext<MessageHub> _hubContext;

        private Timer _timer;
        private List<FaultLargeGroup> faultList;
        private Dictionary<string, List<FaultLargeGroup>>? stationGroup;
        private List<FaultSubclassDetails> faultSubclassDetailAllList;

        public ExecuteFaultWork(
            IFaultLargeGroupService faultLargeGroupService,
            IFaultSubclassDetailsService faultSubclassDetailsService,
            IFaultLogService faultLogService,
            IHubContext<MessageHub> hubContext
            )
        {
            _faultLargeGroupService = faultLargeGroupService;
            _faultSubclassDetailsService = faultSubclassDetailsService;
            _faultLogService = faultLogService;
            _hubContext = hubContext;
        }

        public void ExecuteImport()
        {
            return;
            string[]? lines = CurrentOPInfo.Current.WorkStationConfig?.Select(s => s.ProductionLineCode).ToArray();
            faultList = _faultLargeGroupService.QueryByLine(lines);
            stationGroup = faultList.GroupBy(gb => gb.StationCode)
                  .ToDictionary(s => s.Key, s => s.ToList());
            faultSubclassDetailAllList = _faultSubclassDetailsService.QueryAll();
            TimeSpan _interval = TimeSpan.FromMilliseconds(200);
            _timer = new Timer(x =>
            {
                Task.Run(() =>
                {
                    try
                    {
                        _ = FaultListenerAsync();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error: {ex.Message}");
                    }
                });
            }, null, TimeSpan.Zero, _interval);
        }

        /// <summary>
        /// 已连接设备故障监听
        /// </summary>
        /// <returns></returns>
        private async Task FaultListenerAsync()
        {
            try
            {
                var currentPairs = new ConcurrentDictionary<int, byte[]>();
                var oldPairs = new ConcurrentDictionary<int, byte[]>();

                var tasks = stationGroup?.Select(async pairs =>
                {
                    var stationTasks = pairs.Value.Select(async item =>
                    {
                        byte[] stationFault = await CurrentAppInfo.Current.communicationPairs[item.StationCode]
                            .ReadDbBlockAsync(item.DbBlock, item.DbStartByte, item.ByteCount);
                        return (item.ByteNo, stationFault);
                    });

                    var results = await Task.WhenAll(stationTasks);
                    foreach (var (byteNo, stationFault) in results)
                    {
                        currentPairs[byteNo] = stationFault;
                    }
                    var detailTasks = currentPairs.Select(pair =>
                    {
                        var faultSubclassDetailsList = faultSubclassDetailAllList
                            .Where(fa => fa.ByteNo.Equals(pair.Key))
                            .ToList();

                        return Task.WhenAll(faultSubclassDetailsList.Select(async detail =>
                        {
                            bool BitLeft = (pair.Value[detail.FaultNo / 8] & (1 << (detail.FaultNo % 8))) != 0;
                            bool BitRight = oldPairs.TryGetValue(pair.Key, out byte[]? bytes) && bytes != null && bytes.Length > (detail.FaultNo / 8)
                                ? (bytes[detail.FaultNo / 8] & (1 << (detail.FaultNo % 8))) != 0
                                : false;

                            if (BitLeft != BitRight)
                            {
                                var oldFaultLog = await _faultLogService.QueryInfoByFaultNoAsync(detail.ItemNo);
                                if (oldFaultLog != null)
                                {
                                    _ = ReceiveMessageAsync(detail.ContextEn);
                                    //更新历史警告
                                    //DateTime startTime = oldFaultLog.TimeOn;
                                    //oldFaultLog.TimeEnd = DateTime.Now;
                                    //var interval = (DateTime.Now - startTime).Seconds;
                                    //oldFaultLog.Interval = interval;
                                    //oldFaultLog.State = 2;
                                    //_faultLogService.Update(oldFaultLog);
                                }
                                else
                                {
                                    _ = ReceiveMessageAsync(detail.ContextEn);

                                    // 插入新警告
                                    //FaultLog logInfo = new FaultLog();
                                    //logInfo.ProductionLine = detail.ProductionLine;
                                    //logInfo.StationCode = detail.StationCode;
                                    //logInfo.FaultNo = detail.ItemNo;
                                    //logInfo.TimeOn = DateTime.Now;
                                    //logInfo.State = 1;
                                    //_faultLogService.Insert(logInfo);
                                }
                            }
                        }));
                    });

                    await Task.WhenAll(detailTasks);
                    foreach (var (byteNo, stationFault) in results)
                    {
                        oldPairs[byteNo] = stationFault;
                    }
                });
                await Task.WhenAll(tasks);
            }
            catch
            {
            }
        }

        /// <summary>
        /// 转发前端
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private async Task ReceiveMessageAsync(string message)
        {
            try
            {
                await _hubContext.Clients.All.SendAsync("receiveNotice", "Error", $"{message}");
            }
            catch (Exception) { throw; }
        }

        public void CommunicationDefault_plc_dataChange(string stationType, INormCommunication communication, int itemNo, string address, object value)
        {
        }
    }
}